package com.talkweb.securitycamera.module;

import com.talkweb.securitycamera.cameraInterface.ICameraModule;
import com.talkweb.securitycamera.cameraInterface.ICameraConfigChangeCallback;
import com.talkweb.securitycamera.cameraInterface.ICameraReset;
import com.talkweb.securitycamera.common.constans.FileType;
import com.talkweb.securitycamera.common.interfaces.dataprocess.IFileGet;
import ohos.agp.graphics.Surface;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;
import ohos.media.camera.device.Camera;
import ohos.media.camera.device.FrameConfig;
import ohos.media.common.AudioProperty;
import ohos.media.common.Source;
import ohos.media.common.StorageProperty;
import ohos.media.common.VideoProperty;
import ohos.media.image.common.Size;
import ohos.media.recorder.Recorder;

import java.io.File;

import static ohos.media.camera.device.Camera.FrameConfigType.FRAME_CONFIG_RECORD;

/**
 * @version 1.0.1
 * @description:相机录像模块
 * @program: security-camera
 * @Author xiaozhijun
 * @Date 2021/3/03 14:12
 */
public class CameraRecordModule implements ICameraModule, Recorder.IRecorderListener, ICameraConfigChangeCallback {

    private Recorder mediaRecorder; // 录像操作对象
    private Source source; // 音视频源
    private AudioProperty.Builder audioPropertyBuilder; // 音频属性
    private VideoProperty.Builder videoPropertyBuilder; // 视频属性
    private StorageProperty.Builder storagePropertyBuilder; // 音视频存储属性
    private Context mContext;
    private IFileGet mVideoFileGet;//获取缓存文件
    private Surface mPresurface;//预览surface
    private Camera mCamera;//相机
    private ICameraReset mCameraReset;//相机配置重置接口对象
    private Size mPreSize;//预览尺寸
    private boolean isStop = false;//是否停止了录像

    public CameraRecordModule(Context context, ICameraReset cameraReset) {
        this.mContext = context;
        this.mCameraReset = cameraReset;
    }

    @Override
    public Surface getSurface() {
        return mediaRecorder.getVideoSurface();
    }

    @Override
    public void start(Camera camera, Surface surface) {
        this.mCamera = camera;
        mPresurface = surface;
        //判断是否调用了stop停止录像
        if (!isStop) {
            //开始修改莫模板，录制
            changeFrameConfig(camera);
            mediaRecorder.start();
        } else {
            //停止录像后需要重置相机配置和重新初始化Recorder
            initMediaRecorder(mPreSize);
            if (mCameraReset != null) {
                mCameraReset.resetCamera();
            }
        }

    }

    @Override
    public void stop(Camera camera) {
        isStop = true;
        mediaRecorder.stop();
        mediaRecorder.registerRecorderListener(null);
        mediaRecorder.release();
    }

    /**
     * 初始化录像
     *
     * @param properSize
     */
    private void initMediaRecorder(Size properSize) {
        videoPropertyBuilder = new VideoProperty.Builder();
        audioPropertyBuilder = new AudioProperty.Builder();
        storagePropertyBuilder = new StorageProperty.Builder();
        mediaRecorder = new Recorder();
        source = new Source();
        videoPropertyBuilder.setRecorderBitRate(10000000); // 设置录制比特率
        int rotation = DisplayManager.getInstance().getDefaultDisplay(mContext).get().getRotation();
        videoPropertyBuilder.setRecorderDegrees(rotation); // 设置录像方向
        videoPropertyBuilder.setRecorderFps(30); // 设置录制采样率
        videoPropertyBuilder.setRecorderHeight(properSize.height); // 设置录像支持的分辨率，需保证width > height
        videoPropertyBuilder.setRecorderWidth(properSize.width);
        videoPropertyBuilder.setRecorderVideoEncoder(Recorder.VideoEncoder.DEFAULT); // 设置视频编码方式
        videoPropertyBuilder.setRecorderRate(30); // 设置录制帧率
        source.setRecorderAudioSource(Recorder.AudioSource.MIC); // 设置录制音频源
        source.setRecorderVideoSource(Recorder.VideoSource.SURFACE); // 设置视频窗口
        mediaRecorder.setSource(source); // 设置音视频源
        mediaRecorder.setOutputFormat(Recorder.OutputFormat.MPEG_4); // 设置音视频输出格式

        storagePropertyBuilder.setRecorderFile(getFile()); // 设置存储音视频文件名
        storagePropertyBuilder.setRecorderMaxDurationMs(60 * 1000);
        mediaRecorder.setStorageProperty(storagePropertyBuilder.build());
        audioPropertyBuilder.setRecorderAudioEncoder(Recorder.AudioEncoder.AAC); // 设置音频编码格式
        mediaRecorder.setAudioProperty(audioPropertyBuilder.build()); // 设置音频属性
        mediaRecorder.setVideoProperty(videoPropertyBuilder.build()); // 设置视频属性
        mediaRecorder.registerRecorderListener(this);

        mediaRecorder.prepare(); // 准备录制
    }

    @Override
    public File getFile() {
        if (mVideoFileGet != null) {
            return mVideoFileGet.createSourceFile(FileType.FILE_TYPE_VIDEO);
        }
        return null;
    }

    @Override
    public void init(Size properSize, IFileGet fileGet) {
        this.mVideoFileGet = fileGet;
        this.mPreSize = properSize;
        initMediaRecorder(properSize);
    }

    @Override
    public ICameraConfigChangeCallback getConfigChangeCallback() {
        return this;
    }


    @Override
    public void changeFrameConfig(Camera mCamera) {
        // 获取录像配置模板
        FrameConfig.Builder framePictureConfigBuilder = mCamera.getFrameConfigBuilder(FRAME_CONFIG_RECORD);
        framePictureConfigBuilder.addSurface(mPresurface);
        // 配置录像 Surface
        framePictureConfigBuilder.addSurface(getSurface());
        try {
            // 启动循环帧捕获
            int id = mCamera.triggerLoopingCapture(framePictureConfigBuilder.build());
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onError(int i, int i1) {
    }

    @Override
    public void onMessage(int what, int entra) {
        //判断是否达到最大时长/文件长
        if (what == Recorder.RecorderOnInfoType.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED
                || what == Recorder.RecorderOnInfoType.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {
            stop(mCamera);
            //延时200ms后继续录像
            mContext.getUITaskDispatcher().delayDispatch(() -> {
                start(mCamera, mPresurface);
            },200);
        }
    }

    public void setVideoFileGet(IFileGet videoFileGet) {
        this.mVideoFileGet = videoFileGet;
    }

    @Override
    public void onCameraConfigChange(Camera camera) {
        changeFrameConfig(camera);
        mediaRecorder.start();
    }
}
